package l1j.server.server.clientpackets;

import java.util.EnumMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.Config;
import l1j.server.server.datatables.SprTable;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_SystemMessage;
import static l1j.server.server.model.skill.L1SkillId.加速器檢測;

/**
 * 加速器の使用をチェックするクラス。
 */
public class AcceleratorChecker {

	//public static enum ACT_TYPE {MOVE, ATTACK, SPELL_DIR, SPELL_NODIR}
	public static enum ACT_TYPE {MOVE, ATTACK}

	private static final Logger _log = Logger.getLogger(AcceleratorChecker.class.getName());

	private final L1PcInstance _pc;

	//	private int _injusticeCount;

	private int _attackCount;

	private int _attackTotalInterval;

	//	private int _justiceCount;

	/**移動速度連續次數*/
	private int _moveCount;

	private int _moveTotalInterval;

	private int _totalMoveRightInterval;
	
	private int _totalAttackRightInterval;

	//	private static final int INJUSTICE_COUNT_LIMIT = Config.INJUSTICE_COUNT;

	//	private static final int JUSTICE_COUNT_LIMIT = Config.JUSTICE_COUNT;


	// 実際には移動と攻撃のパケット間隔はsprの理論値より5%ほど遅い。
	// それを考慮して-5としている。
		private static final double CHECK_STRICTNESS = Config.CHECK_STRICTNESS / 100D;

	public static final int R_OK = 0;// 正常

	public static final int R_DETECTED = 1;// 異常

	public static final int R_DISCONNECTED = 2;// 連續異常

	private final EnumMap<ACT_TYPE, Long> _actTimers = new EnumMap<ACT_TYPE, Long>(ACT_TYPE.class);

	private final EnumMap<ACT_TYPE, Long> _checkTimers = new EnumMap<ACT_TYPE, Long>(ACT_TYPE.class);


	public AcceleratorChecker(final L1PcInstance pc) {
		this._pc = pc;
		//		this._injusticeCount = 0;
		//		this._justiceCount = 0;
		final long now = System.currentTimeMillis();
		for (final ACT_TYPE each : ACT_TYPE.values()) {
			this._actTimers.put(each, now);
			this._checkTimers.put(each, now);
		}
	}
	private int _rightMoveCount;
	private int _errorMoveCount;
	private int _rightAttackCount;
	private int _errorAttackCount;
	private int _lastMoveRightInterval;
	private int _lastAttackRightInterval;
	private int _continuousMoveCount;//連續異常
	private int _continuousAttackCount;//連續異常
	/**
	 * 封包速度正常與否的檢測
	 * @param type 檢測類型
	 * @return 0:正常 1:異常 2:連續異常
	 */
	public int checkInterval(final ACT_TYPE type) {
		int result = R_OK;
		final long now = System.currentTimeMillis();
		long interval = now - this._actTimers.get(type);
		final int rightInterval = this.getRightInterval(type);
		final boolean log = this._pc.hasSkillEffect(加速器檢測);
		//				System.out.println(interval+" / "+rightInterval);
		if(log){
			if(this._pc.msg ==null){
				this._pc.msg = new StringBuilder(512);
			}
			this._pc.msg.append("IP:(").append(this._pc.getNetConnection().getIp().toString()).append(")	名稱: ")
			.append(this._pc.getName()).append("	類型: ").append(type).append("	速度:	")
			.append(interval).append("	標準:	").append(rightInterval).append("\r\n");
		}
		if(type.equals(ACT_TYPE.MOVE)){
			if(_lastMoveRightInterval != rightInterval){
				_lastMoveRightInterval = rightInterval;
				return result;
			}
			if(interval >1){
				_moveCount++;
				_moveTotalInterval += interval;
				_totalMoveRightInterval += rightInterval;
				_continuousMoveCount += (interval < rightInterval? 1 : -1);
			}
			if(_moveCount>=5){
				if(_continuousMoveCount >= _moveCount-1){
					_log.log(Level.WARNING,"要求角色移動:速度異常(" +_pc.getName() + ")連續異常次數:"+_moveCount);
					this.doDisconnect();
					return R_DISCONNECTED;
				}else if((_moveTotalInterval / _moveCount) + 20 >= _totalMoveRightInterval / _moveCount){
					_moveCount =0;
					_moveTotalInterval=0;
					_totalMoveRightInterval=0;
					_continuousMoveCount=0;
					_rightMoveCount++;
					if(_rightMoveCount >=2){
						_rightMoveCount=0;
						_errorMoveCount=0;
					}
				}else if(_errorMoveCount ==0){
					_errorMoveCount++;
					_rightMoveCount =0;
					_continuousMoveCount=0;
					if(!log){
						this._pc.setSkillEffect(加速器檢測, 60000);
					}
					_log.log(Level.WARNING,"要求角色移動:速度異常(" +_pc.getName() + ")平均值異常X1。");
					return R_DETECTED;
				}else{
					_log.log(Level.WARNING,"要求角色移動:速度異常(" +_pc.getName() + ")平均值異常X2 踢除。");
					this.doDisconnect();
					return R_DISCONNECTED;
				}
			}
		}
		//		


		else if (type.equals(ACT_TYPE.ATTACK))  {
			interval *= CHECK_STRICTNESS;
			if(_lastAttackRightInterval != rightInterval){
				_lastAttackRightInterval = rightInterval;
				return result;
			}
			if(interval >1){
				_attackCount++;
				_attackTotalInterval += interval;
				_totalAttackRightInterval += rightInterval;
				_continuousAttackCount += (interval < rightInterval? 1 : -1);
			}
			if(_attackCount>=5){
				if(_continuousAttackCount >= _attackCount-1){
					_log.log(Level.WARNING,"要求角色攻擊:速度異常(" +_pc.getName() + ")連續異常次數:"+_attackCount);
					this.doDisconnect();
					return R_DISCONNECTED;
				}else if((_attackTotalInterval / _attackCount) + 10 >= _totalAttackRightInterval / _attackCount){
					_attackCount =0;
					_attackTotalInterval=0;
					_totalAttackRightInterval=0;
					_continuousAttackCount=0;
					_rightAttackCount++;
					if(_rightAttackCount >=2){
						_rightAttackCount=0;
						_errorAttackCount=0;
					}
				}else if(_errorAttackCount ==0){
					_errorAttackCount++;
					_rightAttackCount =0;
					_continuousAttackCount=0;
					if(!log){
						this._pc.setSkillEffect(加速器檢測, 60000);
					}
					_log.log(Level.WARNING,"[攻擊]速度異常(" +_pc.getName() + ")平均值異常X1。");
					return R_DETECTED;
				}else{
					_log.log(Level.WARNING,"[攻擊]速度異常(" +_pc.getName() + ")平均值異常X2 踢除。");
					this.doDisconnect();
					return R_DISCONNECTED;
				}
			}
		}
		//				if (1 < interval && interval < rightInterval) {//低於標準值
		//				if(this._pc.msg ==null){
		//					this._pc.msg = new StringBuilder(512);
		//				}
		//				this._AttackinjusticeCount++;
		//				if(this._AttackinjusticeCount >=7){
		//					this.doDisconnect();
		//					return R_DISCONNECTED;
		//				}
		//				this._actTimers.put(type, now);
		//				return R_DISCONNECTED;
		//				}else if (interval >= rightInterval) {//大於或等於標準值
		//					if (type.equals(ACT_TYPE.ATTACK))  {
		//						this._AttackjusticeCount++;
		//						if(this._AttackjusticeCount >=5){
		//							this._AttackinjusticeCount = 0;
		//							this._AttackjusticeCount= 0;
		//						}
		//					}
		//				}
		//			}
		//			if(interval < rightInterval/4){ 
		//				this._actTimers.put(type, now);
		//				return result;
		//			}


		//			else if(type.equals(ACT_TYPE.MOVE)){
		//				_moveCount++;//移動速度連續錯誤次數++
		//				if(_moveCount >=4){
		//					this.doDisconnect();
		//					this._actTimers.put(type, now);
		//					return R_DISCONNECTED;
		//				}
		//			}

		//			this._injusticeCount++;
		//			this._justiceCount = 0;
		//			if (this._injusticeCount >= INJUSTICE_COUNT_LIMIT) {// 允許錯誤次數
		//				if(type.equals(ACT_TYPE.MOVE)){
		//					this._actTimers.put(type, now);
		//					if(!log){
		//						this._pc.setSkillEffect(加速器檢測, 60000);
		//					}
		//					this.doDisconnect();
		//					this._actTimers.put(type, now);
		//					this._injusticeCount = 0;
		//					return R_DISCONNECTED;
		//				}
		//				this.doDisconnect();
		//				this._actTimers.put(type, now);
		//				return R_DISCONNECTED;
		//			}
		//			result = R_DETECTED;
		//		} else
		//			else if(type.equals(ACT_TYPE.MOVE)){
		//				_moveCount =0;//移動速度連續錯誤次數歸零
		//			}
		//			this._justiceCount++;
		//			if (this._justiceCount >= JUSTICE_COUNT_LIMIT) {// 連續正常 恢復計算
		//				this._injusticeCount = 0;
		//				this._justiceCount = 0;
		//			}

		//	System.out.println(interval+" / "+rightInterval+"  正確:"+this._justiceCount+" 異常:"+this._injusticeCount);

		// 検証用
		/*	 double rate = (double) interval / rightInterval;
		 System.out.println(String.format("%s: %d / %d = %.2f (o-%d x-%d)",
		 type.toString(), interval, rightInterval, rate,
		 _justiceCount, _injusticeCount));
		 */
		this._actTimers.put(type, now);
		return result;
	}

	/**
	 * 斷開用戶
	 */
	private void doDisconnect() {
		if (!this._pc.isGm()) {
			this._pc.sendPackets(new S_ServerMessage(945)); // 違法プログラムが見つかったので、終了します。
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO 自動產生的 catch 區塊
				e.printStackTrace();
			}
			this._pc.getNetConnection().close();// 中斷
			this._actTimers.clear();
			_log.info(String.format("加速器檢測通知%s被強制中斷連線。", this._pc.getName()));
		} else {
			// GMは切断しない
			this._pc.sendPackets(new S_SystemMessage("加速器被檢測到了。但GM不受影響。"));
			_moveCount =0;
			_moveTotalInterval=0;
			_totalMoveRightInterval=0;
			_rightMoveCount=0;
			_errorMoveCount=0;
			_continuousMoveCount=0;
			//			this._injusticeCount = 0;
		}
	}

	/**
	 * 正常的速度
	 * @param type 檢測類型
	 * @return 正常應該接收的速度(MS)
	 */
	private int getRightInterval(final ACT_TYPE type) {
		int interval;

		switch (type) {
		case ATTACK:
			interval = SprTable.getInstance().getAttackSpeed(this._pc.getTempCharGfx(), this._pc.getCurrentWeapon() + 1);
			break;
		case MOVE:
			interval = SprTable.getInstance().getMoveSpeed(this._pc.getTempCharGfx(), this._pc.getCurrentWeapon());
			break;
			/*	case SPELL_DIR:
			interval = SprTable.getInstance().getDirSpellSpeed(_pc.getTempCharGfx());
			break;
		case SPELL_NODIR:
			interval = SprTable.getInstance().getNodirSpellSpeed(_pc.getTempCharGfx());
			break;*/
		default:
			return 0;
		}
		// 一段加速
		switch (this._pc.getMoveSpeed()) {
		case 1: // 加速術
			interval *= 0.75;
			break;
		case 2: // 緩速術
			interval /= 0.55;
			break;
		default:
			break;
		}
		switch (this._pc.getBraveSpeed()) {
		case 1: // 勇水
			interval *= 0.755; // 攻速、移速 * 1.33倍
			break;
		case 3: // 精餅
			interval *= 0.855; // 攻速、移速 * 1.15倍
			break;
		case 4: // 神疾、風走、行走
			if (type.equals(ACT_TYPE.MOVE)) {
				interval *= 0.755; // 移速 * 1.33倍
			}
			break;
		case 6: // 血之渴望
			if (type.equals(ACT_TYPE.ATTACK)) {
				interval *= 0.755; // 攻速 * 1.33倍
			}
			break;
		default:
			break;
		}
		/*if (_pc.isHaste()) {// ヘイスト
			interval *= HASTE_RATE;
		}
		if (_pc.isBrave()) { // ブレイブポーション
			interval *= HASTE_RATE;
		}
		if (_pc.isElfBrave()) { // エルヴンワッフル
			interval *= WAFFLE_RATE;
		}
		if (type.equals(ACT_TYPE.MOVE) && _pc.isFastMovable()) {
			// ホーリーウォーク、ウィンドウォーク、ムービングアクセレーション
			interval *= HASTE_RATE;
		}
		if (type.equals(ACT_TYPE.ATTACK) && _pc.isFastAttackable()) {
			//TODO 嗜血
			interval *= HASTE_RATE * WAFFLE_RATE;
		}*/

		// 風之枷鎖
		if (this._pc.isWindShackle() && !type.equals(ACT_TYPE.MOVE)) { // 攻速or施法速度 / 2倍
			interval /= 2;
		}

		if(type.equals(ACT_TYPE.MOVE)){
			interval *=this._pc.getMoveSpeedRate();
		}else if(type.equals(ACT_TYPE.ATTACK)){
			interval *=this._pc.getAttackSpeedRate();
		}
		/*	switch(_pc.isThirdSpeed()){
		case 1://opqlo 3段加速
			interval *= 0.855;//(331) 193%
			break;
		case 2:// oplqo 4段加速
			interval *= 0.47;//(241) 265%
			break;
		case 3:// oplqo 4.5段加速
			interval *= 0.41;//(221) 289%
			break;
		case 4:// oplqo 5段加速
			interval *= 0.33;// (161) 397%
			break;
		}*/
		return interval;
	}
}
